<template>
  <j-modal
    destroyOnClose
    width="1200px"
    :title="title"
    :visible="visible"
    :maskClosable="false"
    :confirmLoading="confirmLoading"
    @ok="handleOk"
    @cancel="handleCancel"
    cancelText="关闭">
    <template slot="footer">
      <a-button @click="handleCancel">关闭</a-button>
      <a-button v-if="!disableSubmit" type="primary" :loading="confirmLoading" @click="handleOk">保存</a-button>
      <div v-if="aiTestMode" style="display: inline-block;float:left">
        <a-select v-model="aiTestTable" placeholder="请选择测试的表类型" style="width: 250px;margin:0 10px 0 20px">
          <a-select-option v-for="(item,index) in aiTableList" :key="index" :value="item.name" >{{ item.title+'('+item.name+')' }}</a-select-option>
        </a-select>
        <a-button type="primary" @click="initVirtualData" ghost>生成数据>></a-button>
      </div>
    </template>
    <a-spin :spinning="confirmLoading">
      <a-form :form="form" layout="inline" :class="{'online-config-cust':true }">
        <a-list>
          <!-- 表名、表描述、表类型 -->
          <a-list-item>
            <a-row style="width: 100%;">
              <a-col :span="24">
                <a-row style="width: 100%;">
                  <a-col :span="addFlag ? 24 : 12">
                    <a-form-item
                      style="width: 100%;"
                      :labelCol="threeCol.label"
                      :wrapperCol="addFlag ? { span: 18 } : threeCol.wrapper"
                      label="表名称">
                      <a-input placeholder="请输入表名称" :disabled="!!model.tableName" v-decorator="['tableName', validatorRules.tableName ]"/>
                    </a-form-item>
                  </a-col>
                  <a-col v-show="!addFlag" :span="12">
                    <a-form-item
                      style="width: 100%;"
                      :labelCol="threeCol.label"
                      :wrapperCol="threeCol.wrapper"
                      label="数据源编码">
                      <a-input placeholder="请输入数据源编码" :disabled="!!model.dataSource" v-decorator="['dataSource', {initialValue: '' } ]"/>
                    </a-form-item>
                  </a-col>
                </a-row>
              </a-col>
              <a-col :span="24">
                <a-row style="width: 100%;">
                  <a-col :span="24">
                    <a-form-item
                      style="width: 100%;"
                      :labelCol="addFlag ? threeCol.label : oneCol.label"
                      :wrapperCol="addFlag ? { span: 18 } : { span: 22 }"
                      label="数据表描述">
                      <a-textarea placeholder="请输入数据表描述" :disabled="disableSubmit" v-decorator="['tableComment', validatorRules.tableComment ]" />
                    </a-form-item>
                  </a-col>
                </a-row>
              </a-col>
              <a-col :span="24">
                <a-row style="width: 100%;">
                    <a-col v-show="!addFlag" :span="12">
                      <a-form-item
                        style="width: 100%;"
                        :labelCol="threeCol.label"
                        :wrapperCol="threeCol.wrapper"
                        label="表类型">
                        <a-select :disabled="!!model.tableType" @change="handleChangeInTableType" v-decorator="[ 'tableType', { initialValue: 3 }]">
                          <a-select-option :value="1">单表</a-select-option>
                          <a-select-option :value="2">主表</a-select-option>
                          <a-select-option :value="3">附表</a-select-option>
                        </a-select>
                      </a-form-item>
                  </a-col>
                   <a-col :span="addFlag ? 24 : 12">
                    <a-form-item style="width: 100%;" :labelCol="threeCol.label" :wrapperCol="addFlag ? { span: 18 } : threeCol.wrapper" label="是否启用">
                       <a-radio-group name="radioGroup" v-decorator="['status', { initialValue: 1 }]" :disabled="disableSubmit || model.tableType!=='3'">
                          <a-radio :value="1">启用</a-radio>
                          <a-radio :value="0">停用</a-radio>
                        </a-radio-group>
                    </a-form-item>
                  </a-col>
                </a-row>
              </a-col>
              <a-col :span="24">
                <a-row style="width: 100%;">
                  <a-col :span="addFlag ? 24 : 12">
                    <a-form-item
                      style="width: 100%;"
                      :labelCol="threeCol.label"
                      :wrapperCol="threeCol.wrapper"
                      label="是否指标">
                      <j-dict-select-tag @change="changeIndexOrNotFlag" type="radio" :trigger-change="true" v-decorator="['indexOrNot', validatorRules.indexOrNot]" placeholder="请选择是否指标" dict-code="index_or_not" />
                    </a-form-item>
                  </a-col>
                  <a-col v-show="indexOrNotFlag == 1" :span="addFlag ? 24 : 12">
                    <a-form-item style="width: 100%;" label="所属专题" :labelCol="threeCol.label" :wrapperCol="threeCol.wrapper">
                      <a-tree-select
                        multiple
                        placeholder="请选择所属专题"
                        style="width: 80%;"
                        :replaceFields="replaceFields"
                        :dropdownStyle="{ maxHeight: '200px', overflow: 'auto' }"
                        :treeData="topicTypes"
                        v-decorator="['topicType']">
                      </a-tree-select>
                    </a-form-item>
                  </a-col>
                  <a-col v-show="indexOrNotFlag == 1" :span="addFlag ? 24 : 12">
                    <a-form-item
                      style="width: 100%;"
                      :labelCol="threeCol.label"
                      :wrapperCol="addFlag ? { span: 18 } : threeCol.wrapper"
                      label="数据更新频率">
                      <j-dict-select-tag :trigger-change="true" v-decorator="['dataFrequency', validatorRules.dataFrequency]" placeholder="请选择数据更新频率" dict-code="data_frequency" :disabled="disableSubmit" />
                    </a-form-item>
                  </a-col>
                </a-row>
              </a-col>
            </a-row>
          </a-list-item>
        </a-list>
      </a-form>
        <a-spin :spinning="tableLoading">
          <a-tabs v-model="activeKey" @change="handleChangeInTabs">
            <a-tab-pane tab="数据库属性" key="1" :forceRender="true">
              <db-attribute-table
                ref="table1"
                :action-button="disableSubmit || (model.tableType!=='3' && !addFlag)"
                :operate-button="operateType"
                @added="handleAdded"
                @deleted="handleDeleted"
                @dragged="handleDragged"
                @inserted="handleInserted" />
          </a-tab-pane>
        </a-tabs>
      </a-spin>
    </a-spin>
  </j-modal>
</template>

<script>
import pick from 'lodash.pick'
import DBAttributeTable from '../tables/DBAttributeTable'
import { setDataSource, getMasterTableInitialData, getTreeNeedFields } from '../util/TableUtils'
import { validateTables, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
import { randomUUID, simpleDebounce } from '@/utils/util.js'
import { AiTestOnlineMixin } from '@/views/modules/aitest/onlinetest.mixins'
import { getAction, httpAction } from '@/api/manage'

export default {
  name: 'OnlCgformHeadModal',
  components: { 'db-attribute-table': DBAttributeTable },
  mixins: [AiTestOnlineMixin],
  provide() {
    return {
      getAllTable: this.getAllTable
    }
  },
  data() {
    return {
      title: '操作',
      visible: false,
      activeKey: '1',
      model: {},
      showRelationType: false,
      showTreeParentIdField: false,
      showIdSequence: false,
      showSubTable: false,
      disableSubmit: false,
      operateType: 0,
      oneCol: {
        label: { span: 2 },
        wrapper: { span: 24 - 2 }
      },
      threeCol: {
        label: { span: 4 },
        wrapper: { span: 20 }
      },
      confirmLoading: false,
      tableLoading: false,
      form: this.$form.createForm(this),
      validatorRules: {
        tableName: {
          rules: [{
            required: true, message: '请输入表名!'
          }, {
            validator: this.validateTableName
          }]
        },
        tableComment: {
          rules: [{
            required: true, message: '请输入数据表描述!'
          }]
        },
        dataFrequency: {
          rules: [{
            required: true, message: '请选择数据更新频率!'
          }]
        }
      },
      url: {
        add: '/dataSource/scSituationTable/createNewTable', // /add',
        edit: '/dataSource/scSituationTable/edit',
        queryField: '/index/config/getColumns',
        checkOnlyTable: '/dataSource/scSituationTable/checkOnlyTable'
      },
      treeFieldAdded: false,
      // 树形列表需要的配置ID集合
      tree_field_id: [],
      // 未验证通过
      VALIDATE_NO_PASSED: Symbol(),
      // editPageFlag: false,
      // 立即同步所有 table（防抖版）
      syncAllTableNowDebounce: simpleDebounce(() => {
        this.syncAllTableNowPromise()
      }, 150),
      // 临时 id 不保存到数据库
      fieldTempIds: [],
      showDesFormCode: false,
      templateFlag: false,
      // 原表名
      metaTableName: '',
      addFlag: false,
      indexOrNotFlag: 1,
      topicTypes: [],
      replaceFields: {
        children: 'childList',
        title: 'catalogName',
        key: 'id',
        value: 'id'
      }
    }
  },
  created() {
    this.getTopicTypes()
  },
  methods: {
    getTopicTypes() {
      this.topicTypes = []
      getAction('/index/config/queryIndexCatalog', {}).then((res) => {
        if (res.success) {
          this.topicTypes = res.result
        }
      })
    },
    changeIndexOrNotFlag(val) {
      this.indexOrNotFlag = val
    },
    /**
      * 获取指定的 $refs 对象
      * 有时候可能会遇到组件未挂载到页面中的情况，导致无法获取 $refs 中的某个对象
      * 这个方法可以等待挂载完成之后再返回 $refs 的对象，避免报错
      * @author sunjianlei
      */
    getRefPromise(name) {
      const _this = this
      return new Promise((resolve) => {
        (function next() {
          const ref = _this.$refs[name]
          if (ref) {
            resolve(ref)
          } else {
            setTimeout(() => { next() }, 10)
          }
        })()
      })
    },
    add() {
      this.treeFieldAdded = false
      this.addFlag = true
      // this.editPageFlag = false
      // 添加初始数据
      this.getAllTable().then(tables => {
        const [table] = tables
        // 临时 id，不保存到数据库
        const tempIds = []
        const datas = getMasterTableInitialData()
        datas.forEach(data => {
          data.id = randomUUID()
          tempIds.push(data.id)
        })
        this.fieldTempIds = tempIds
        const data = [{
          id: datas[0].id,
          columnName: datas[0].dbFieldName,
          columnComment: datas[0].dbFieldTxt,
          columnLength: datas[0].dbLength,
          scale: datas[0].dbPointLength,
          defaultValue: datas[0].dbDefaultVal,
          columnType: datas[0].dbType,
          isPk: datas[0].dbIsKey,
          isNullable: datas[0].dbIsNull,
          sort: 0
        }]
        setTimeout(() => {
          setDataSource(table, data)
        }, 0)
      })
      this.edit({ indexOrNot: 1 }, 'add')
    },
    edit(record, caller = '') {
      this.metaTableName = ''
      this.initialAllTable()
      this.activeKey = '1'
      this.visible = true
      // 设置主表的数据
      this.form.resetFields()

      this.model = Object.assign({}, record)

      this.indexOrNotFlag = this.model.indexOrNot

      // 处理所属专题
      if (this.model.indexOrNot == 1 && this.model.catalogId != null && this.model.catalogId != '') {
        this.model.topicType = this.model.catalogId.split(',')
      }
      this.treeFieldAdded = record.isTree == 'Y'
      const pickAfter = pick(this.model, 'tableName', 'dataSource', 'tableComment', 'status', 'indexOrNot', 'topicType')
      this.tableJsonGetHelper(pickAfter)
      this.initialAllShowItem(pickAfter)
      this.$nextTick(() => {
        this.form.setFieldsValue(pickAfter)
        this.metaTableName = pickAfter['tableName']
      })
      // 不是添加，就加载数据库中的数据
      if (caller !== 'add') {
        this.tableLoading = true
        this.addFlag = false
        // 如果版本号为1 表示未曾修改 未曾同步 可以修改表名
        // this.editPageFlag = this.model.tableVersion != 1
        Promise.all([
          getAction(this.url.queryField, { tableId: this.model.id }),
          this.getRefPromise('table1')
        ]).then(results => {
          const [{ result: fields }, table1] = results
          console.log('fields', fields)
          this.fieldsJsonGetHelper(fields)
          table1.deleteIds = []
          table1.selectedRowKeys = []
          // 将数据同步到各表中
          setDataSource(table1, fields, true)
        }).catch(e => {
          console.error(e)
        }).then(() => {
          this.tableLoading = false
        })
      }
    },
    close() {
      this.$emit('close')
      this.visible = false
    },
    handleOk() {
      this.validateFields()
    },
    handleCancel() {
      this.close()
    },
    /**
     * 初始化所有需要条件切换显示的项
     */
    initialAllShowItem(record) {
      this.handleChangeInTableType(record.tableType || 1)
      this.handleChangeInIsTree(record.isTree || 'N')
      this.handleChangeInIdType(record.idType || 'UUID')
      this.showSubTable = (record.tableType || 1) === 2
      this.handleChangeInIsDesForm(record.isDesForm || 'N')
    },
    handleChangeInTableType(value) {
      if (value === 1) {
        this.templateFlag = true
      } else {
        this.templateFlag = false
      }
      this.showRelationType = (value === 3)
    },
    handleChangeInIsTree(value) {
      this.showTreeParentIdField = (value === 'Y')
      if (value === 'Y') {
        this.addTreeNeedField()
      } else {
        this.deleteTreeNeedField()
      }
    },
    handleChangeInIdType(value) {
      this.showIdSequence = (value === 'SEQUENCE')
    },
    /**
     * 获取所有的表
     */
    getAllTable() {
      return Promise.all([
        this.getRefPromise('table1')
      ])
    },
    /**
     * 初始化所有的table
     */
    initialAllTable() {
      this.getAllTable().then(tables => {
        tables.forEach(table => {
          table.$refs.editableTable.initialize()
        })
      })
    },
    /**
     * ATab切换事件
     */
    handleChangeInTabs(activeKey) {
      // 当切换了选项卡的时候只同步修改当前所能看到的table
      if (['2', '3', '4', '5', '6'].indexOf(activeKey) !== -1) {
        Promise.all([
          this.getRefPromise('table1'),
          this.getRefPromise(`table${activeKey}`)
        ]).then(tables => {
          const [table1, table] = tables
          table1.$refs.editableTable.resetScrollTop()
          table.syncTable(table1)
        })
      }
    },
    /**
     * 当新增了的时候应立即同步
     */
    handleAdded() {
      this.syncAllTableNow()
    },
    /**
     * 当删除的时候也应立即同步
     */
    handleDeleted() {
      this.syncAllTableNow()
    },
    /**
     * 当拖动后立即同步
     */
    handleDragged(event) {
      const { oldIndex, newIndex, target } = event
      this.syncAllOrderNumNow(oldIndex, newIndex)
    },
    /**
     * 当插入后立即同步
     */
    handleInserted(event) {
      const { insertIndex, target } = event
      this.syncAllTableNowPromise().then(res => {
        const oldIndex = target.$refs.editableTable.rows.length - 1
        this.syncAllOrderNumNow(oldIndex, insertIndex)
      })
    },
    /**
     * 立即同步所有的表的排序顺序
     */
    syncAllOrderNumNow(oldIndex, newIndex) {
      this.getAllTable().then(tables => {
        tables.forEach((tab, idx) => {
          if (idx > 0 && idx < 4) {
            tab.$refs.editableTable.rowResort(oldIndex, newIndex)
          }
        })
      })
    },
    /**
     * 立即主动同步所有table
     */
    syncAllTableNow() {
      this.syncAllTableNowDebounce()
    },
    // 立即同步所有 table （返回Promise）
    syncAllTableNowPromise() {
      return this.getAllTable().then(tables => {
        return new Promise(async(resolve, reject) => {
          const [table1] = tables
          resolve()
        })
      })
    },
    /**
     * 触发所有表单验证
     */
    validateFields() {
      this.form.validateFields((err, values) => {
        if (!err) {
          this.validateTableFields().then(table => {
            this.confirmLoading = true
            const formData = Object.assign(this.model, values)
            let httpUrl = this.url.add
            let method = 'post'
            if (this.model.id) {
              httpUrl = this.url.edit
              method = 'put'
              formData['code'] = undefined // 由于编码的特殊性，所以不能更改
            }

            if (formData.indexOrNot == 1 && formData.topicType != null && formData.topicType.length > 0) {
              formData.catalogId = formData.topicType.join(',')
            } else {
              formData.catalogId = ''
            }

            const tableColumns = table.table1.values
            const oldColumns = this.$refs.table1.dataSource
            tableColumns.forEach(item => {
              const oldColumn = oldColumns.find(item1 => item1.columnName == item.columnName)
              item.id = oldColumn != undefined ? oldColumn.id : null
            })
            formData.columns = tableColumns
            httpAction(httpUrl, formData, method).then((res) => {
              if (res.success) {
                this.$message.success(res.message)
                this.$emit('ok')
                this.close()
              } else {
                this.$message.warning(res.message)
              }
            }).finally(() => {
              this.confirmLoading = false
            })
          })
        }
      })
    },
    /**
     * 发起请求新增或修改的请求
     */
    requestAddOrEdit(formData) {
      this.confirmLoading = true
      // update-begin-author:taoyan date:20190924 for:表字段转小写
      if (formData.fields && formData.fields.length > 0) {
        for (const i of formData.fields) {
          i.dbFieldName = i.dbFieldName.toLowerCase()
        }
      }
      if (formData.head && formData.head.tableName) {
        formData.head.tableName = formData.head.tableName.toLowerCase().trim()
      }
      // update-end-author:taoyan date:20190924 for:表字段转小写
      // 判断是add还是edit
      let method = 'post'; let url = this.url.addAll
      if (this.model.id) {
        method = 'put'
        url = this.url.editAll
      }
      // 发起请求
      // console.log("formData.....",formData)
      httpAction(url, formData, method).then((res) => {
        if (res.success) {
          this.refreshCacheTableName(this.metaTableName, formData.head['tableName'])
          this.$message.success(res.message)
          this.$emit('ok')
          this.close()
        } else {
          this.$message.warning(res.message)
        }
      }).finally(() => {
        this.confirmLoading = false
      })
    },
    /**
     * 将五个表的数据整理整合成后台识别的formData
     */
    classifyIntoFormData(options) {
      // 整理数据
      const formData = { head: {}, fields: [], indexs: [] }
      formData.head = Object.assign(this.model, options.values)
      // 整理 fields
      options.table1.values.forEach((item, index) => {
        // ID 以 table1 的 ID 为准
        const rowId = item.id
        const field = Object.assign({}, item)
        field['order_num'] = index
        // 如果 table1 没有返回id，则代表是新增的数据
        if (rowId == null || rowId === '') {
          delete field.id
        } else {
          field.id = rowId
        }
        // 去掉临时ID
        if (this.fieldTempIds.includes(field.id)) {
          delete field.id
        }
        formData.fields.push(field)
      })
      formData.deleteFieldIds = options.table1.deleteIds
      return formData
    },
    /**
     * 验证并获取五个表的数据
     */
    validateTableFields() {
      const _this = this
      return new Promise((resolve, reject) => {
        this.getAllTable().then((tables) => {
          const cases = []
          for (const table of tables) {
            cases.push(table.$refs.editableTable)
          }
          return validateTables(cases, true)
        }).then((all) => {
          const options = {}
          all.forEach((item, index) => {
            options[`table${index + 1}`] = item
          })
          resolve(options)
        }).catch((e = {}) => {
          // 判断表单验证是否未通过
          if (e.error === VALIDATE_NO_PASSED) {
            // 未通过就跳转到相应的tab选项卡
            _this.activeKey = (e.index + 1).toString()
          }
          reject(e)
        })
      })
    },
    validateTableName(rule, value, callback) {
      if (!value) {
        callback()
      } else {
        const part1 = new RegExp('^[a-zA-Z].*')
        const part2 = new RegExp('^[a-zA-Z]{1}_.*')
        const part3 = new RegExp('^[0-9].*')
        const part4 = new RegExp('[\u4E00-\u9FA5]')
        const part5 = new RegExp('^[0-9]*$')
        const part6 = new RegExp('^[a-zA-Z][a-zA-Z0-9_]*$')
        if (value.length > 30) {
          callback('长度不能超过30')
        } else if (!part1.test(value)) {
          callback('必须以字母开头')
        } else if (part2.test(value)) {
          callback('不能以单个字母加下划线开头')
        } else if (part3.test(value)) {
          callback('不能以数字开头')
        } else if (part4.test(value)) {
          callback('不能包含汉字')
        } else if (part5.test(value)) {
          callback('不能全部是数字')
        } else if (!part6.test(value)) {
          callback('不能包含特殊符号')
        } else {
          const params = {
            id: !this.model.id ? '' : this.model.id,
            tbname: value
          }
          getAction(this.url.checkOnlyTable, params).then(res => {
            if (res.success && res.result === -1) {
              callback('表名已存在')
            } else {
              callback()
            }
          }).catch(() => {
            callback()
          })
        }
      }
    },
    deleteTreeNeedField() {
      if (this.tree_field_id && this.tree_field_id.length > 0) {
        this.getAllTable().then((tables) => {
          const [table1] = tables
          table1.tableDeleteLines(this.tree_field_id)
          this.tree_field_id = []
          this.treeFieldAdded = false
        })
      }
    },
    addTreeNeedField() {
      if (!this.treeFieldAdded) {
        this.getAllTable().then((tables) => {
          const [table1] = tables
          let datas = getTreeNeedFields()
          datas = datas.filter(item => {
            const nameList = table1.dataSource.map(o => o.dbFieldName)
            return !nameList.includes(item.dbFieldName)
          })
          this.tree_field_id = []
          datas.forEach((newData) => {
            const uuidTemp = randomUUID() + '__tempid'
            this.tree_field_id.push(uuidTemp)
            newData.id = uuidTemp
          })
          table1.$refs.editableTable._pushByDataSource(datas)
          this.$nextTick(() => this.syncAllTableNow())
        })
        this.treeFieldAdded = true
      }
      this.$nextTick(() => {
        this.form.setFieldsValue({ 'treeIdField': 'has_child', 'treeParentIdField': 'pid' })
      })
    },
    handleChangeInIsDesForm(value) {
      this.showDesFormCode = (value === 'Y')
    },
    handleChangeTableName(e) {
      this.metaTableName = e.target.value
    }
  }
}
</script>

<style scoped>
::v-deep .ant-form-inline .ant-form-item-with-help {
  margin-bottom: 0
}

::v-deep .ant-modal-body {
  height: 100%;
}

.online-config-cust .has-feedback{
  display: block !important;
}

.input-table .thead .td span{
  width:100%;
}
</style>
